Skip to content
标签
数据库
字数
1715 字
阅读时间
8 分钟

一、概述

Spring对数据库的操作在jdbc上面做了基本的封装,让开发者在操作数据库时只需关注SQL语句和查询 结果处理器,即可完成功能(当然,只使用JdbcTemplate,还不能摆脱持久层实现类的编写)。

在配合spring的IoC功能,可以把DataSource注册到JdbcTemplate之中。同时利用spring基于 aop的事务即可完成简单的数据库CRUD操作。

JdbcTemplate的限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用 JdbcTemlate需要导入spring-jdbc和spring-tx两个坐标。

1.1 相关方法

JdbcTemplate实现了JdbcOperations接口,操作方法都定义在此接口中
JdbcTemplate主要提供以下五类方法: 
	execute方法: 可以用于执行任何SQL语句,一般用于执行DDL语句; 
	update方法及batchUpdate方法: update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语 句; 
	query方法及queryForXXX方法: 用于执行查询相关语句; 
	call方法: 用于执行存储过程、函数相关语句。

1.2 NamedParameterJdbcTemplate

在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制. 定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定.在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择 是使用具名参数(named parameter).

那么什么是具名参数?

具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定. 具名参数更易于维护, 也提升了可读性. 具名 参数由框架类在运行时用占位符取代

具名参数只在 NamedParameterJdbcTemplate 中得到支持。

NamedParameterJdbcTemplate可以使 用全部jdbcTemplate方法。

NamedParameterJdbcTemplate里面封装了一个JdbcTemplate对象

二、使用示例

2.1 自定义JdbcTemplate

依赖

xml
<dependencies> 
    <dependency>
        <groupId>com.alibaba</groupId> 
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency> 
    <dependency> 
        <groupId>mysql</groupId> 
        <artifactId>mysql-connector-java</artifactId> 
        <version>5.1.45</version> 
    </dependency> 
</dependencies>

自定义jdbcTemplate

java
package com.itheima.jdbc;

import com.itheima.jdbc.handler.ResultSetHandler;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * 自定义JdbcTemplate
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class JdbcTemplate {

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public JdbcTemplate(){

    }

    public JdbcTemplate(DataSource dataSource){
        setDataSource(dataSource);
    }

    /**
     * 用于执行增删改方法的
     * @param sql       执行的SQL语句
     * @param params    执行SQL所需的参数
     * @return          影响数据库记录的行数
     */
    public int update(String sql,Object... params){
        //1.验证数据源是否有值
        if(dataSource == null){
            throw new NullPointerException("DataSource can not be null!");
        }
        //2.定义jdbc操作的相关对象
        Connection conn = null;
        PreparedStatement pstm = null;
        int res = 0;
        try{
            //3.获取连接
            conn = dataSource.getConnection();
            //4.获取预处理对象
            pstm = conn.prepareStatement(sql);
            //5.获取参数的元信息
            ParameterMetaData pmd = pstm.getParameterMetaData();
            //6.获取sql域中参数的个数
            int parameterCount = pmd.getParameterCount();
            //7.判断sql语句中是否有参数
            if(parameterCount > 0){
                //判断是否提供了参数
                if(params == null){
                    throw new IllegalArgumentException("Parameter can not be null!");
                }
                //判断是否个数匹配
                if(parameterCount != params.length){
                    throw new IllegalArgumentException("Incorrect parameter size: expected "+String.valueOf(parameterCount)+", actual "+String.valueOf(params.length));
                }
                //参数校验通过,给占位符赋值
                for(int i=0;i<parameterCount;i++){
                    pstm.setObject(i+1,params[i]);
                }
            }
            //8.执行sql语句
            res = pstm.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            release(null,pstm,conn);
        }
        return res;
    }

    /**
     * 执行查询方法
     * @param sql       执行的语句
     * @param rsh       处理结果集的封装,此处只是提供一个规范(接口),由使用者编写具体的实现
     * @param params    执行语句所需的参数
     * @return
     */
    public Object query(String sql, ResultSetHandler rsh, Object... params){
        //1.验证数据源是否有值
        if(dataSource == null){
            throw new NullPointerException("DataSource can not be null!");
        }
        //2.定义jdbc操作的相关对象
        Connection conn = null;
        PreparedStatement pstm = null;
        ResultSet rs = null;
        try{
            //3.获取连接
            conn = dataSource.getConnection();
            //4.获取预处理对象
            pstm = conn.prepareStatement(sql);
            //5.获取参数的元信息
            ParameterMetaData pmd = pstm.getParameterMetaData();
            //6.获取sql域中参数的个数
            int parameterCount = pmd.getParameterCount();
            //7.判断sql语句中是否有参数
            if(parameterCount > 0){
                //判断是否提供了参数
                if(params == null){
                    throw new IllegalArgumentException("Parameter can not be null!");
                }
                //判断是否个数匹配
                if(parameterCount != params.length){
                    throw new IllegalArgumentException("Incorrect parameter size: expected "+String.valueOf(parameterCount)+", actual "+String.valueOf(params.length));
                }
                //参数校验通过,给占位符赋值
                for(int i=0;i<parameterCount;i++){
                    pstm.setObject(i+1,params[i]);
                }
            }
            //8.执行sql语句
            rs = pstm.executeQuery();
            //9.封装
            return rsh.handle(rs);
        }catch (Exception e){
           throw new RuntimeException(e);
        }finally {
            release(rs,pstm,conn);
        }
    }


    private void release(ResultSet rs,PreparedStatement pstm ,Connection conn){
        if(rs != null){
            try {
                rs.close();
            }catch (Exception e){
                e.printStackTrace();
            }

        }

        if(pstm != null){
            try {
                pstm.close();
            }catch (Exception e){
                e.printStackTrace();
            }

        }

        if(conn != null){
            try {
                conn.close();
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }
}

自定义RowMapper

java
package com.itheima.jdbc.handler;

import java.sql.ResultSet;

/**
 * 结果集的处理器
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public interface ResultSetHandler {

    /**
     * 处理结果集
     * @param rs
     * @return
     */
    Object handle(ResultSet rs);
}

提供不同实现

java
package com.itheima.jdbc.handler.impl;

import com.itheima.jdbc.handler.ResultSetHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

/**
 * 封装到实体类中的结果集处理器
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class BeanHandler<T> implements ResultSetHandler {

    //定义封装哪个实体类的子接口
    private Class<T> requiredType;

    /**
     * 当创建BeanHandler对象时,就需要提供封装到的实体类字节码
     * @param requiredType
     */
    public BeanHandler(Class requiredType){
        this.requiredType = requiredType;
    }

    @Override
    public Object handle(ResultSet rs) {
        //1.定义返回值
        T bean = null;
        try{
            //2.判断是否有结果集
            if(rs.next()){
                //3.实例化返回值对象
                bean = requiredType.newInstance();
                //4.获取结果集的元信息
                ResultSetMetaData rsmd = rs.getMetaData();
                //5.获取结果集的列数
                int columnCount = rsmd.getColumnCount();
                //6.遍历列的个数
                for(int i=0;i<columnCount;i++){
                    //7.取出列的标题
                    String columnLabel = rsmd.getColumnLabel(i+1);
                    //8.取出当前列标题对应的数据内容
                    Object value = rs.getObject(columnLabel);
                    //9.借助java的内省机制,使用属性描述器填充
                    PropertyDescriptor pd = new PropertyDescriptor(columnLabel,requiredType);
                    //10.获取属性的写方法
                    Method method = pd.getWriteMethod();
                    //11.执行方法
                    method.invoke(bean,value);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }
}
java
package com.itheima.jdbc.handler.impl;

import com.itheima.jdbc.handler.ResultSetHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class BeanListHandler<T> implements ResultSetHandler {


    //定义封装哪个实体类的子接口
    private Class<T> requiredType;

    /**
     * 当创建BeanHandler对象时,就需要提供封装到的实体类字节码
     * @param requiredType
     */
    public BeanListHandler(Class requiredType){
        this.requiredType = requiredType;
    }

    @Override
    public Object handle(ResultSet rs) {
        //1.定义返回值
        List list = new ArrayList<>();
        T bean = null;
        try{
            //2.遍历结果集
            while(rs.next()){
                //3.实例化返回值对象
                bean = requiredType.newInstance();
                //4.获取结果集的元信息
                ResultSetMetaData rsmd = rs.getMetaData();
                //5.获取结果集的列数
                int columnCount = rsmd.getColumnCount();
                //6.遍历列的个数
                for(int i=0;i<columnCount;i++){
                    //7.取出列的标题
                    String columnLabel = rsmd.getColumnLabel(i+1);
                    //8.取出当前列标题对应的数据内容
                    Object value = rs.getObject(columnLabel);
                    //9.借助java的内省机制,使用属性描述器填充
                    PropertyDescriptor pd = new PropertyDescriptor(columnLabel,requiredType);
                    //10.获取属性的写方法
                    Method method = pd.getWriteMethod();
                    //11.执行方法
                    method.invoke(bean,value);
                }
                //12.把填充好的bean封装到集合中
                list.add(bean);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return list;
    }
}